//! @Author: DengLibin 
//! @Date:  2022-04-22 14:13:12
//! @Description: json

use actix_web::{
    error, get, http::header::ContentType, http::StatusCode, post, web, Error, HttpResponse,
    ResponseError, Scope,
};
use futures_util::StreamExt as _;
use json::JsonValue;
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::vec;

use serde_json::{json, to_string_pretty};
const MAX_SIZE: usize = 262_144; // max payload size is 256k
#[derive(Debug, Serialize, Deserialize)]
struct User {
    id: i32,
    likes: Vec<String>,
}
#[derive(Debug, Serialize, Deserialize)]
struct MyObj {
    name: String,
    number: i32,
    users: Vec<User>,
}

// 自定义错误
#[derive(Debug, Serialize)]
struct MyError {
    msg: String, //错误信息
    status: u16, // 状态码（作为http的响应状态码）
}
impl Display for MyError {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{}", to_string_pretty(self).unwrap())
    }
}
// 实现ResponseError
impl ResponseError for MyError {
    // builds the actual response to send back when an error occurs
    fn error_response(&self) -> HttpResponse {
        let err_json = json!({ "error": self.msg });
        HttpResponse::build(StatusCode::from_u16(self.status).unwrap()).json(err_json)
    }
}

/// @Author: DengLibin 
/// @Date:  2022-04-21 11:33:27
/// @Description: 路由配置
pub fn route() -> Scope {
    let prodcuts_scope = web::scope("/json");

    prodcuts_scope
        .service(get_my_obj)
        .service(post_my_obj)
        .service(payload_json)
        .service(post_json_body)
        .service(my_error_json)
}

/// 返回json
#[get("/get_my_obj")]
async fn get_my_obj() -> HttpResponse {
    let mut users: Vec<User> = vec![];
    let mut likes = vec![String::from("footbball")];
    likes.push("swiming".to_string());
    users.push(User {
        id: 1,
        likes: likes,
    });

    let my_obj = MyObj {
        name: String::from("李四"),
        number: 23,
        users: users,
    };

    HttpResponse::Ok().json(my_obj) // <- send response
}

/// 接收json
/// This handler uses json extractor
#[post("/post_my_obj")]
async fn post_my_obj(item: web::Json<MyObj>) -> HttpResponse {
    info!("model: {:?}", &item);
    HttpResponse::Ok().json(item.0) // <- send response
}

/// This handler manually load request payload and parse json object
/// 手动转json
#[post("/payload_json")]
async fn payload_json(mut payload: web::Payload) -> Result<HttpResponse, Error> {
    // payload is a stream of Bytes objects
    let mut body = web::BytesMut::new();
    while let Some(chunk) = payload.next().await {
        let chunk = chunk?;
        // limit max size of in-memory payload
        if (body.len() + chunk.len()) > MAX_SIZE {
            return Err(error::ErrorBadRequest("overflow"));
        }
        body.extend_from_slice(&chunk);
    }
    // body is loaded, now we can deserialize serde-json
    let obj = serde_json::from_slice::<MyObj>(&body)?;
    Ok(HttpResponse::Ok().json(obj)) // <- send response
}

/// This handler manually load request payload and parse json-rust
/// 使用json模块解析
#[post("/post_json_body")]
async fn post_json_body(body: web::Bytes) -> Result<HttpResponse, Error> {
    // body is loaded, now we can deserialize json-rust
    let result = json::parse(std::str::from_utf8(&body).unwrap()); // return Result
    let injson: JsonValue = match result {
        Ok(v) => v,
        Err(e) => json::object! {"err" => e.to_string() },
    };
    Ok(HttpResponse::Ok()
        //.content_type("application/json")
        .content_type(ContentType::json())
        .body(injson.dump()))
}
/// @Author: DengLibin 
/// @Date:  2022-04-24 12:07:02
/// @Description: 自定义错误
#[get("error_json")]
async fn my_error_json() -> Result<HttpResponse, MyError> {
    // 返回一个错误，先交给错误捕捉中间件处理， 如果中间件不能处理才返回给前端
    Err(MyError {
        msg: "an example error message".to_string(),
        status: 401,
    })
}
